package com.woody.aggregate.application.service.msgsendrule.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woody.aggregate.domain.settings.SysCategoryConfigManager;
import com.woody.aggregate.application.service.msgsendrule.converter.MsgSendRuleConverter;
import com.woody.aggregate.domain.msgsendrule.MsgSendRuleManager;
import com.woody.aggregate.domain.msgsendrule.MsgSendRuleTargetRefManager;
import com.woody.aggregate.application.service.msgsendrule.IMsgSendRuleService;
import com.woody.aggregate.infrastructure.settings.entity.SysCategoryConfig;
import com.woody.aggregate.infrastructure.messagebox.dto.MessageboxCountDTO;
import com.woody.aggregate.infrastructure.messagebox.mapper.MessageboxConfigMapper;
import com.woody.aggregate.infrastructure.msgsendrule.dto.MsgSendRuleInfoDTO;
import com.woody.aggregate.infrastructure.msgsendrule.dto.SaveMsgSendRuleDTO;
import com.woody.aggregate.infrastructure.msgsendrule.entity.MsgSendRule;
import com.woody.aggregate.infrastructure.msgsendrule.entity.MsgSendRuleTargetRef;
import com.woody.aggregate.msgsendrule.enums.MsgSendStartTypeEnum;
import com.woody.aggregate.msgsendrule.enums.MsgSendUserScopeEnum;
import com.woody.aggregate.msgsendrule.req.ListMsgSendRuleReq;
import com.woody.aggregate.msgsendrule.vo.MsgSendRuleVo;
import com.woody.base.exception.BaseException;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 消息弹窗规则 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-03-20
 */
@Service
public class MsgSendRuleServiceImpl implements IMsgSendRuleService {

    @Autowired
    private MessageboxConfigMapper messageboxConfigMapper;

    @Autowired
    private MsgSendRuleManager ruleManager;

    @Autowired
    private MsgSendRuleTargetRefManager ruleTargetRefManager;

    @Autowired
    private SysCategoryConfigManager categoryConfigManager;
    @Autowired
    private MsgSendRuleManager msgSendRuleManager;


    /**
     * 分页查询弹窗规则列表
     * <br />
     *
     * @param request
     * @return
     */
    @Override
    public Page<MsgSendRuleVo> pageListRule(ListMsgSendRuleReq request) {
        Page<MsgSendRuleInfoDTO> sendRuleDtoPage = ruleManager.pageQuerySendRule(request.genPage(), request.getCategoryId(), request.getRuleName());

        Page<MsgSendRuleVo> pageVo = new Page<>(sendRuleDtoPage.getCurrent(), sendRuleDtoPage.getSize(), sendRuleDtoPage.getTotal());
        if (CollectionUtils.isEmpty(sendRuleDtoPage.getRecords())) {
            return pageVo;
        }

        // 查询规则绑定的弹窗统计
        List<MessageboxCountDTO> countDtos = new ArrayList<>();
        if (request.isGetBindingCount()) {
            List<Integer> ruleIds = sendRuleDtoPage.getRecords().stream().map(MsgSendRuleInfoDTO::getId).collect(Collectors.toList());
            countDtos = messageboxConfigMapper.countByRuleIds(ruleIds);
        }

        // 将 MsgSendRule 转换为 MsgSendRuleVo
        pageVo.setRecords(MsgSendRuleConverter.convertToVoList(sendRuleDtoPage.getRecords(), countDtos));
        return pageVo;
    }

    /**
     * 查询规则详情
     * <br />
     *
     * @param ruleId
     * @return
     */
    @Override
    public MsgSendRuleInfoDTO queryRuleDetailById(Integer ruleId) {
        return ruleManager.getMsgSendRuleDtoByRuleId(ruleId);
    }

    /**
     * 新增规则
     * <br />
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer addRule(SaveMsgSendRuleDTO dto, Collection<Long> userIds) {
        preCheckSaveRule(null, dto);

        Date createTime = new Date();

        MsgSendRule entity = new MsgSendRule();
        entity.setTitle(dto.getRuleName());
        entity.setCategoryId(dto.getCategoryId());
        entity.setStartType(dto.getStartType());
        entity.setStartTime(Optional.ofNullable(dto.getStartTime()).orElse(createTime));
        entity.setFrequency(dto.getFrequency());
        entity.setUserScope(dto.getUserScope());
        entity.setUserType(dto.getUserType());
        entity.setCreateUserId(dto.getOperatorUserId());
        entity.setUpdateUserId(dto.getOperatorUserId());
        entity.setCreateTime(createTime);
        entity.setUpdateTime(createTime);

        if (!ruleManager.save(entity)) {
            throw new BaseException("规则创建失败");
        }

        Integer ruleId = entity.getId();

        // 如果是精准推送，保存精准推送的用户信息
        if (MsgSendUserScopeEnum.SPECIFY.getScope().equals(dto.getUserScope()) && CollectionUtils.isNotEmpty(userIds)) {
            List<MsgSendRuleTargetRef> targetInfoList = userIds.stream().map(uid -> {
                return new MsgSendRuleTargetRef(){{
                    setRuleId(ruleId);
                    setTargetType(dto.getUserType());
                    setBizId(uid);
                    setCreateUserId(dto.getOperatorUserId());
                    setCreateTime(createTime);
                }};
            }).collect(Collectors.toList());
            ruleTargetRefManager.saveBatch(targetInfoList);
        }

        return ruleId;
    }

    /**
     * 更新规则
     *
     * @param ruleId
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editRule(Integer ruleId, SaveMsgSendRuleDTO dto) {
        preCheckSaveRule(ruleId, dto);

        MsgSendRule rule = ruleManager.getById(ruleId);
        if (rule == null) {
            throw new BaseException("规则不存在或已删除");
        }

        Integer oldUserScope = rule.getUserScope();

        // 全部推送不能修改成精准推送。精准推送可以修改成全部推送
        if (MsgSendUserScopeEnum.ALL.getScope().equals(oldUserScope) && MsgSendUserScopeEnum.SPECIFY.getScope().equals(dto.getUserScope())) {
            throw new BaseException("全部推送不能修改成精准推送");
        }

        // 更新时间
        Date updateTime = new Date();

        rule.setTitle(dto.getRuleName());
        rule.setCategoryId(dto.getCategoryId());
        rule.setFrequency(dto.getFrequency());
        rule.setUserType(dto.getUserType());
        rule.setUserScope(dto.getUserScope());
        rule.setUpdateUserId(dto.getOperatorUserId());
        rule.setUpdateTime(updateTime);

        // 推送时间类型变化
        if (!rule.getStartType().equals(dto.getStartType())) {
            rule.setStartType(dto.getStartType());

            if (MsgSendStartTypeEnum.TIMING.getType().equals(dto.getStartType())) {
                // 立即推送变定时推送
                rule.setStartTime(dto.getStartTime());
            } else if (MsgSendStartTypeEnum.IMMEDIATELY.getType().equals(dto.getStartType())) {
                // 定时推送变立即推送
                rule.setStartTime(updateTime);
            }
        }

        if (!ruleManager.updateById(rule)) {
            return;
        }

        // 推送用户范围发生变化
        if (!oldUserScope.equals(rule.getUserScope())) {
            // 精准推送变全部推送，删除原推送用户
            if (MsgSendUserScopeEnum.ALL.getScope().equals(dto.getUserScope())) {
                LambdaQueryWrapper<MsgSendRuleTargetRef> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(MsgSendRuleTargetRef::getRuleId, ruleId);
                ruleTargetRefManager.remove(queryWrapper);
            }
        }
    }

    /**
     * 删除规则
     * <br />
     *
     * @param ruleId
     */
    @Override
    public void deleteRule(Integer ruleId) {
        // 校验规则是否被弹窗使用
        List<MessageboxCountDTO> dtos = messageboxConfigMapper.countByRuleIds(Collections.singletonList(ruleId));
        if (CollectionUtils.isNotEmpty(dtos)) {
            throw new BaseException("规则已绑定弹窗，无法删除");
        }

        // 删除规则
        msgSendRuleManager.removeById(ruleId);

    }


    /**
     * <pre>
     *     新增、编辑规则时，前置校验：
     *     1. 分类是否存在
     *     2. 是否重名
     *     3. 如果是编辑，校验绑定该规则的弹窗是否全部已禁用
     * </pre>
     * @param selfId 可以为null
     * @param dto
     */
    private void preCheckSaveRule(Integer selfId, SaveMsgSendRuleDTO dto) {
        // 1. 分类是否存在
        SysCategoryConfig categoryConfig = categoryConfigManager.getById(dto.getCategoryId());
        if (categoryConfig == null) {
            throw new BaseException("分类不存在或已被删除");
        }

        // 2. 是否重名
        LambdaQueryWrapper<MsgSendRule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ne(selfId != null, MsgSendRule::getId, selfId)
                .eq(MsgSendRule::getTitle, dto.getRuleName());

        if (ruleManager.count(queryWrapper) > 0) {
            throw new BaseException("规则名称已存在");
        }

        // 3. 如果是编辑，校验规则是否存在启用中的弹窗，所有弹窗禁用后才可以编辑
        if (selfId != null && selfId > 0) {
            // 校验规则是否被弹窗使用
            List<MessageboxCountDTO> dtos = messageboxConfigMapper.countByRuleIds(Collections.singletonList(selfId));
            // 弹窗状态：1=启用；0=禁用
            if (dtos.stream().anyMatch(o -> o.getStatus().equals(1) && o.getNum() > 0)) {
                throw new BaseException("该规则存在启用中的弹窗，请禁用后再编辑");
            }
        }
    }
}
